﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;

namespace PluginDB
{
    public class TVShowsRepository
    {
        private readonly Repository<TVShow, PluginDbEntities> _tvShowRepository;
        private readonly Repository<TVShowsLink, PluginDbEntities> _tvShowsLinkRepository;
        private readonly Repository<Series, PluginDbEntities> _seriesRepository;
        private readonly CommonRepository _commonRepository;

        public TVShowsRepository(PluginDbEntities pluginDbEntities)
        {
            _tvShowRepository = new Repository<TVShow, PluginDbEntities>(pluginDbEntities);
            _tvShowsLinkRepository = new Repository<TVShowsLink, PluginDbEntities>(pluginDbEntities);
            _seriesRepository = new Repository<Series, PluginDbEntities>(pluginDbEntities);
            _commonRepository = new CommonRepository(pluginDbEntities);
        }

        public bool IsSeriesExists(string seriesName)
        {
            return _seriesRepository.DoQuery().Any(a => a.Name.ToLower().Equals(seriesName.ToLower()));
        }

        public bool IsTVShowExists(string pluginUrl)
        {
            return _tvShowRepository.DoQuery(
                new Specification<TVShow>(v => v.PluginUrl.ToLower() == pluginUrl.ToLower())).Any();
        }

        public Series CreateSeries(string name)
        {
            var series = new Series
            {
                Name = name,
            };

            _seriesRepository.Add(series);
            return series;
        }

        public Series GetSeries(long seriesId)
        {
            return _seriesRepository.DoQuery(new Specification<Series>(a => a.SeriesID == seriesId)).FirstOrDefault();
        }

        public Series GetSeries(string name)
        {
            return _seriesRepository.DoQuery(
                new Specification<Series>(a => a.Name.ToLower().Equals(name.ToLower()))).FirstOrDefault() ??
                           CreateSeries(name);
        }

        public void AddTVShow(PluginVideoInfo pluginVideoInfo)
        {
            try
            {
                var tvShow = new TVShow
                {
                    VideoID = pluginVideoInfo.VideoID,
                    Name = pluginVideoInfo.VideoName,
                    EnglishName = pluginVideoInfo.EnglishVideoName,
                    HebrewName = pluginVideoInfo.HebrewVideoName,
                    ImageUrl = pluginVideoInfo.ImageUrl,
                    PluginUrl = pluginVideoInfo.PluginUrl,
                    Site = _commonRepository.GetSite(pluginVideoInfo.SiteName),
                    SeasonNumber = pluginVideoInfo.TVShowInformation.SeasonNumber,
                    EpisodeNumber = pluginVideoInfo.TVShowInformation.EpisodeNumber,
                    IsHebSub = pluginVideoInfo.IsHebSub
                };

                //Handle links
                foreach (var link in pluginVideoInfo.Links)
                {
                    if (link.IsBrokenLink) continue;

                    tvShow.TVShowsLinks.Add(new TVShowsLink
                    {
                        LinkURL = link.LinkURL,
                        Source = _commonRepository.GetSource(link.SourceName)
                    });
                }

                //Handle Series
                var series = GetSeries(pluginVideoInfo.TVShowInformation.SeriesName);
                if (series.SeriesID == 0 && pluginVideoInfo.TVShowInformation.TVDBInformationItem.IsValid)
                {
                    series.FanartUrl = pluginVideoInfo.TVShowInformation.TVDBInformationItem.FanartUrl;
                    series.ImageUrl = pluginVideoInfo.TVShowInformation.TVDBInformationItem.FanartUrl;
                    series.Plot = pluginVideoInfo.TVShowInformation.TVDBInformationItem.Plot;
                }
                tvShow.Series = series;

                //If there is no VALID link in video then dont save it
                if (tvShow.TVShowsLinks.Count == 0)
                {
                    Debug.WriteLine(string.Format("TVShow:{0} has no valid links. abort saving it.", tvShow.Name));
                    return;
                }

                _tvShowRepository.Add(tvShow);
                _tvShowRepository.Save();
            }
            catch (UpdateException ex)
            {
                Console.WriteLine("UpdateException durin update. Ex={0}", ex.InnerException.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception durin Save. Ex={0}", ex.InnerException.Message);
            }
        }

        public List<TVShow> GetLatestVideosList()
        {
            var videos = _tvShowRepository.SelectAll().OrderByDescending(a => a.VideoID);
            return videos.ToList();
        }

        public List<Series> GetHebSubVideos()
        {
            return _tvShowRepository.Session.Series
                                    .Where(v => v.TVShows.Select(t => t.IsHebSub.HasValue && t.IsHebSub == true).Count() > 0)
                                    .OrderBy(v => v.Name).ToList();
        }

        internal List<TVShow> GetTVShowsByCategoryId(long categoryId)
        {
            var videos =
                _tvShowRepository.DoQuery().Where(v => (v.Categories.Where(c => c.CategoryID == categoryId)).Count() > 0);
            return videos.ToList();
        }

        internal List<Series> GetAtoZSeriesList(string startWord)
        {
            var videos = _seriesRepository.SelectAll().OrderBy(s => s.Name).ToList();
            return videos.Where(s => s.Name.StartsWith(startWord)).ToList();
        }

        internal List<Series> GetTVShowsBySite(long siteId)
        {
            var videos = _tvShowRepository.Session.Series
                                        .Where(s => s.TVShows.Where(t=>t.Site.SiteID == siteId).Count() > 0)
                                        .OrderBy(s=>s.Name);
            return videos.ToList();
        }

        internal TVShow GetTVShowByID(long videoId)
        {
            var video = _tvShowRepository.DoQuery(
                new Specification<TVShow>(v => v.VideoID == videoId)).Include("TVShowsLinks").FirstOrDefault();
            return video;
        }

        internal TVShowsLink GetTVShowLinkByID(long linkId)
        {
            var link = _tvShowsLinkRepository.DoQuery(
                new Specification<TVShowsLink>(v => v.LinkID == linkId)).FirstOrDefault();
            return link;
        }

        internal List<Series> GetSeriesList()
        {
            return _seriesRepository.DoQuery().OrderBy(s => s.Name).ToList();
        }

        internal List<TVShow> GetTVShowsBySeries(long seriesId)
        {
            var videos = _tvShowRepository
                .DoQuery()
                .Where(v => (v.Series.SeriesID == seriesId));
            return videos.ToList();
        }

        internal List<long> GetHebSubSeasonsbySeriesId(long seriesId)
        {
            var seasonsList = _tvShowsLinkRepository.Session.TVShows
                .Where(s => s.Series.SeriesID == seriesId && s.IsHebSub.HasValue && s.IsHebSub == true)
                .Select(s => new
                {
                    s.SeasonNumber
                })
                .Distinct();

            return seasonsList.Select(seasonNumber => seasonNumber.SeasonNumber).ToList();
        }

        internal List<long> GetSeasonsbySeriesAndSiteId(long siteId, long seriesId)
        {
            var seasonsList = _tvShowsLinkRepository.Session.TVShows
                .Where(s => s.Series.SeriesID == seriesId && s.Site.SiteID == siteId)
                .Select(s => new
                {
                    s.SeasonNumber
                })
                .Distinct();

            return seasonsList.Select(seasonNumber => seasonNumber.SeasonNumber).ToList();
        }

        internal List<long> GetSeasonsbySeriesId(long seriesId)
        {
            var seasonsList = _tvShowsLinkRepository.Session.TVShows
                .Where(s => s.Series.SeriesID == seriesId)
                .Select(s => new
                {
                    s.SeasonNumber
                })
                .Distinct();

            return seasonsList.Select(seasonNumber => seasonNumber.SeasonNumber).ToList();
        }

        internal List<TVShow> GetHebSubTVShowsBySeasonId(long seriesId, long seasonNumber)
        {
            var tvShows = _tvShowsLinkRepository.Session.TVShows
                            .Where(s => s.Series.SeriesID == seriesId && 
                                        s.SeasonNumber == seasonNumber && 
                                        s.IsHebSub.HasValue && 
                                        s.IsHebSub == true)
                            .OrderBy(s => s.HebrewName);

            return tvShows.ToList();
        }

        internal List<TVShow> GetTVShowsBySeasonAndSiteId(long siteId, long seriesId, long seasonNumber)
        {
            var tvShows = _tvShowsLinkRepository.Session.TVShows
                            .Where(s => s.Series.SeriesID == seriesId && 
                                        s.SeasonNumber == seasonNumber &&
                                        s.Site.SiteID == siteId)
                            .OrderBy(s => s.HebrewName);

            return tvShows.ToList();
        }

        internal List<TVShow> GetTVShowsBySeasonId(long seriesId, long seasonNumber)
        {
            var tvShows = _tvShowsLinkRepository.Session.TVShows
                            .Where(s => s.Series.SeriesID == seriesId &&  s.SeasonNumber == seasonNumber)
                            .OrderBy(s=>s.HebrewName);

            return tvShows.ToList();
        }

        internal List<Series> GetTVShowsBySearchText(string searchText)
        {
            var videos = _seriesRepository.SelectAll().OrderBy(s => s.Name).ToList();
            return videos.Where(s => s.Name.ToLower().Contains(searchText.ToLower())).ToList();

            //var videos = _seriesRepository.Session.Series.Where(
            //    s => s.Name.ToLower().Contains(searchText.ToLower()));
            //return videos.OrderBy(series => series.Name).ToList();
        }
    }
}
